/**
 * @author 码上绝尘
 * @date 2024-11-30 00:34:41
 * @description 封装 axios 请求
 * @see https://juejin.cn/post/7408103832142512165
 * @status done
 */

import axios from 'axios'
import { AxiosHeaders } from 'axios'
import type { InternalAxiosRequestConfig, AxiosResponse } from 'axios'

import emitter from '@/emitter'
import { show_loading, api_fail, api_success } from '@/emitter'
import { localCache } from '../cache'

const { VITE_APP_API_BASE_URL, VITE_API_TIMEOUT } = import.meta.env
const pendingRequests: any = {}

/**
 * 创建 axios 实例
 */
const request = axios.create({
  baseURL: VITE_APP_API_BASE_URL, // 基础路径上会携带/api
  timeout: VITE_API_TIMEOUT
})

// 展示 loading
// const showLoading = () => {
//   loadingInstance = ElLoading.service({
//     lock: true,
//     text: 'Loading...',
//     background: 'rgba(0, 0, 0, 0.5)',
//     spinner: `
//         <svg width="50" height="50" viewBox="0 0 135 135" xmlns="http://www.w3.org/2000/svg" fill="#409eff">
//             <path d="M67.447 58c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10zm9.448 9.447c0 5.523 4.477 10 10 10 5.522 0 10-4.477 10-10s-4.478-10-10-10c-5.523 0-10 4.477-10 10zm-9.448 9.448c-5.523 0-10 4.477-10 10 0 5.522 4.477 10 10 10s10-4.478 10-10c0-5.523-4.477-10-10-10zM58 67.447c0-5.523-4.477-10-10-10s-10 4.477-10 10 4.477 10 10 10 10-4.477 10-10z">
//                 <animateTransform
//                     attributeName="transform"
//                     type="rotate"
//                     from="0 67 67"
//                     to="-360 67 67"
//                     dur="2.5s"
//                     repeatCount="indefinite"/>
//             </path>
//             <path d="M28.19 40.31c6.627 0 12-5.374 12-12 0-6.628-5.373-12-12-12-6.628 0-12 5.372-12 12 0 6.626 5.372 12 12 12zm30.72-19.825c4.686 4.687 12.284 4.687 16.97 0 4.686-4.686 4.686-12.284 0-16.97-4.686-4.687-12.284-4.687-16.97 0-4.687 4.686-4.687 12.284 0 16.97zm35.74 7.705c0 6.627 5.37 12 12 12 6.626 0 12-5.373 12-12 0-6.628-5.374-12-12-12-6.63 0-12 5.372-12 12zm19.822 30.72c-4.686 4.686-4.686 12.284 0 16.97 4.687 4.686 12.285 4.686 16.97 0 4.687-4.686 4.687-12.284 0-16.97-4.685-4.687-12.283-4.687-16.97 0zm-7.704 35.74c-6.627 0-12 5.37-12 12 0 6.626 5.373 12 12 12s12-5.374 12-12c0-6.63-5.373-12-12-12zm-30.72 19.822c-4.686-4.686-12.284-4.686-16.97 0-4.686 4.687-4.686 12.285 0 16.97 4.686 4.687 12.284 4.687 16.97 0 4.687-4.685 4.687-12.283 0-16.97zm-35.74-7.704c0-6.627-5.372-12-12-12-6.626 0-12 5.373-12 12s5.374 12 12 12c6.628 0 12-5.373 12-12zm-19.823-30.72c4.687-4.686 4.687-12.284 0-16.97-4.686-4.686-12.284-4.686-16.97 0-4.687 4.686-4.687 12.284 0 16.97 4.686 4.687 12.284 4.687 16.97 0z">
//                 <animateTransform
//                     attributeName="transform"
//                     type="rotate"
//                     from="0 67 67"
//                     to="360 67 67"
//                     dur="8s"
//                     repeatCount="indefinite"/>
//             </path>
//         </svg>
//     `
//   })
// }

// 关闭 loading
// const hideLoading = () => {
//   if (loadingInstance) {
//     loadingInstance.close()
//   }
// }

/**
 * 生成请求 key
 * @param config 请求配置
 * @returns
 */
const generateRequestKey = (config: InternalAxiosRequestConfig) => {
  const { method, url, params, data } = config
  // 使用时间戳确保每次请求 key 唯一 如果单位时间内防止重复请求的话时间条件和逻辑修改一下
  const timestamp = Date.now()
  return `${method}:${url}:${JSON.stringify(params)}:${JSON.stringify(data)}:${timestamp}`
}

/**
 * 添加请求到 pending 中
 * @param config 请求配置
 */
const addPendingRequest = (config: InternalAxiosRequestConfig) => {
  const requestKey = generateRequestKey(config)
  if (pendingRequests[requestKey]) {
    config.cancelToken = new axios.CancelToken((cancel) => {
      cancel('取消重复请求')
    })
  } else {
    pendingRequests[requestKey] = true
  }
}

/**
 * 移除 pending 中的请求
 * @param config 请求配置
 */
const removePendingRequest = (config: InternalAxiosRequestConfig) => {
  const requestKey = generateRequestKey(config)
  delete pendingRequests[requestKey]
}

/** 请求拦截器 */
request.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // 显示 loading 动画
    // showLoading()
    emitter.emit(show_loading, true)
    // 添加重复请求处理
    addPendingRequest(config)

    // 确保 headers 存在
    if (!config.headers) {
      config.headers = new AxiosHeaders() // 使用 AxiosHeaders 创建 headers
    }

    // 禁用缓存
    config.headers.set('Cache-Control', 'no-cache')
    config.headers.set('Pragma', 'no-cache')
    config.headers.set('Expires', '0')

    // 从 Cookie 中获取 token --- 后端操作Cookie时(后端set Cookie时下面的两段代码不要,删掉)
    const token = localCache.get('TOKEN')

    // 如果 token 存在，将其添加到请求头中
    if (token) {
      config.headers.set('Authorization', `Bearer ${token}`) // 使用 set 方法
    }

    // 文件上传设置
    if (config.headers.get('Content-Type') === 'multipart/form-data') {
      config.headers.set('Content-Type', 'multipart/form-data')
    } else {
      config.headers.set('Content-Type', 'application/json')
    }

    return config
  },
  (error: any) => {
    // hideLoading()
    emitter.emit(show_loading, false)
    return Promise.reject(error)
  }
)

/** 响应拦截器 */
request.interceptors.response.use(
  (response: AxiosResponse) => {
    // 关闭 loading 动画
    // hideLoading()
    emitter.emit(show_loading, false)
    // 移除 pending 请求
    removePendingRequest(response.config)
    const url = response.config.url
    emitter.emit(api_success, url)
    // 响应成功，返回数据
    return response.data
  },
  async (error: any) => {
    // hideLoading()
    emitter.emit(show_loading, false)
    let errorInfo = ''
    const status: number = error.response ? error.response.status : 0
    // const originalRequest = error.config

    // 处理 HTTP 错误状态码
    switch (status) {
      case 401: {
        errorInfo = '未授权，请登录'
        // 自动刷新 token 逻辑 --- 后端操作Cookie时(后端set Cookie时下面的代码不要,逻辑修改一下，直接调用后端刷新接口即可)
        // const refreshToken = setToken(CACHE_KEY.REFRESH_TOKEN);
        // if (refreshToken && !originalRequest._retry) {
        //   originalRequest._retry = true;
        // 这里可以实现刷新 token 的逻辑
        // const newToken = await refreshAccessToken(refreshToken);
        // setToken(newToken);
        // originalRequest.headers["Authorization"] = `Bearer ${newToken}`;
        // return request(originalRequest); // 重新发起请求
        // } else {
        //   // 退出登录
        //   const router = useRouter();
        //   router.push("/login");
        //   location.reload();
        // }
        break
      }
      case 403: {
        errorInfo = '拒绝访问'
        break
      }
      case 404: {
        errorInfo = '请求地址出错'
        break
      }
      case 408: {
        errorInfo = '请求超时'
        break
      }
      case 500: {
        errorInfo = '服务器内部错误'
        break
      }
      case 501: {
        errorInfo = '服务未实现'
        break
      }
      case 502: {
        errorInfo = '网关错误'
        break
      }
      case 503: {
        errorInfo = '服务不可用'
        break
      }
      case 504: {
        errorInfo = '网关超时'
        break
      }
      default: {
        if (
          error.response &&
          error.response.data &&
          error.response.data.message
        ) {
          errorInfo = error.response.data.message // 使用后端返回的错误信息|如res.message，根据后端返回报文数据结构变化....
        } else {
          errorInfo = '其他错误' // 使用默认的本地化信息
        }
        break
      }
    }

    const title = error.code || ''
    // 提示错误信息
    // ElNotification({
    //   message: errorInfo,
    //   type: 'error',
    //   duration: 1 * 1000
    // })
    // 触发API:FAIL事件，传递错误信息和错误状态码
    emitter.emit(api_fail, errorInfo, status, title)

    // 将错误信息返回给前端页面，方便捕获具体的 message
    return Promise.reject(error.response ? error.response.data : error)
  }
)

export default request
